/*
   overrides.c
   Functions in the auto object that override kfuns, usually to add
   security on file-writing operations or other sensitive kfuns.
   These functions all need to be nomask so that they cannot be
   bypassed.
   Begun by Mobydick, 5-24-94.
*/

#include <config.h>
#include <options.h>
#include <type.h>

nomask int valid_write(string file);
nomask int valid_read(string file);

static nomask void write(string str);
static nomask object get_object(string name);

private static string creator;        /* will be set in security.c */
private static string privileges;     /* ditto */

/*
   save_object() checks for permissions to save. Users and players may
   save to the appropriate data file. Any object can save to a file
   which has the same name as the object but ends in .dat instead of .c.
   The mailer can save to /data/mail/foo.dat if its creator is foo, not
   otherwise. The mail daemon can save to /data/mail/foo.dat for any
   value of foo.
   Other save attempts are not permitted.
   Returns 1 if the save was permitted, 0 if not.
*/
static nomask int save_object(string file){
    string s1, s2;
    string obname, prefix;
    int clonenum;

	/* Separate the file name and the clone number. */
    sscanf(object_name(this_object()), "%s#%d", obname, clonenum);
    if(!obname)
    	obname = object_name(this_object());

    switch(obname){
	case USER:/* Users can save to /data/user */
		if(sscanf(file, USER_SAVE_DIR+"%s"+USER_SAVE_EXT, prefix) && prefix == creator){
			::save_object(file);
			return 1;
		}
		return 0;
	case PLAYER:
		if(sscanf(file, PLAYER_SAVE_DIR+"%s"+PLAYER_SAVE_EXT, prefix) && prefix == creator){
			::save_object(file);
			return 1;
		}
		return 0;
	case MAIL_D:
		::save_object(file);
		return 1;
	case MAILER:
		if(file == MAIL_DIR+creator+MAIL_EXT){
			::save_object(file);
			return 1;
		}
	}/***END SWITCH***/

	if(sscanf(file, "%s.dat", s1) && s1 == obname){
	   ::save_object(file);
	   return 1;
	}
  	return 0;

#if 0
	/* Users can save to /data/user. */
    if(obname == USER) {
	if (sscanf(file,USER_SAVE_DIR+"%s.dat",prefix)==1 && prefix==creator) {
	    ::save_object(file) ;
	    return 1 ;
        }
        return 0 ;
    }
/* Players can save to /data/player. */
    if (obname==PLAYER) {
	if (sscanf(file,PLAYER_SAVE_DIR+"%s.dat",prefix)==1 && prefix==creator){
	    ::save_object(file) ;
	    return 1 ;
        }
        return 0 ;
    }
/* The mailer can save to /data/mail/foo.dat if foo is its creator. */
   if (obname==MAILER && file==MAIL_DIR+creator+MAIL_EXT) {
       ::save_object(file) ;
       return 1 ;
   }
/* The mailer daemon can always save. */
   if (obname==MAIL_D) {
       ::save_object(file) ;
       return 1 ;
   }



/* Any object can save to the a file with the same name as that object
   but ending with .dat instead of .c. */
    if (sscanf(file,"%s.dat",s1)==1 && s1==obname) {
	::save_object(file) ;
        return 1 ;
    }
/* For now, no other saves allowed. */
    return 0 ;
#endif
}

/* restore_object() checks to make sure you have read permission to any
   file you restore from. This is necessary to safeguard mail. */
static nomask int restore_object(string file){
#if 0 /* Hymael */
    if (!valid_read(file)) return 0;
#endif

    ::restore_object(file);
    return 1;
}

/* destruct_object() overrides the destruct efun. An object may only destroy
   itself.
*/
static nomask void destruct_object(object obj){
    object env;

	if(object_name(::this_object()) == "/cmds/admin/eval"){
		::destruct_object(obj);
		return;
	}
    if(obj != this_object())
    	return;
	/* If we have an environment, depart therefrom. */
	/* having a problem, somehow, with this_object() being zero in the
       middle of an update. Can't find it, so let's just trap for it. */
    if(!this_object())
    	return;

    env = this_object()->query_environment();
    if(env)
    	env->release_object(this_object());

    ::destruct_object(this_object());
}

/* write_file() calls valid_write() in the previous object to make
   sure the write attempt is legal.  */
static nomask int write_file (varargs string file, string str, int offset) {
    if(!valid_write(file))
    	return 0;

    return ::write_file(file,str,offset);
}

/* read_file() calls valid_read() in the previous object to make
   sure the write attempt is legal.  */
static nomask string read_file(varargs string file, int offset, int size){
    if(!valid_read(file))
    	return nil;

    return ::read_file(file,offset,size);
}

/* remove_file calls valid_write() to check permission.  */
static nomask int remove_file(string file){
    if(!valid_write(file))
    	return 0;

    return ::remove_file(file);
}

/* So does remove_dir. */
static nomask int remove_dir(string directory){
    if(!valid_write(directory))
    	return 0;

    return ::remove_dir(directory);
}

/* What a coincidence! make_dir does too! */
static nomask int make_dir(string directory){
    if(!valid_write(directory))
    	return 0;

    return ::make_dir(directory);
}

/* To no one's surprise, so does rename_file. */
static nomask int rename_file(string old, string new){
    if(!valid_write(old))
    	return 0;

    if(!valid_write(new))
    	return 0;

    return ::rename_file(old,new);
}

/* This masks the clone_object kfun for backward compatibility, so
   that you can send files as well as objects if you want. */
static nomask object clone_object(mixed master){
    if(typeof(master) == T_STRING)
        master = get_object(master);

    return ::clone_object(master);
}

/* This is here to impose limits on resource usage. A call_out
   can start a function call in any object, so the auto.c object
   needs to have an rlimits() call that will be invoked in every
   object when a call_out is made. The idea is to override the
   call_out kfun, redirecting the call_out to a limit_call_out
   function that imposes the rlimits() and then sends control
   to the originally called function.
   I thank harte@xs4all.nl (Erwin Harte) for this idea.

static nomask varargs int call_out (string func, int delay, mixed args) {
write ("func is "+func+" and delay is "+delay+"\n") ;
    return ::call_out("limit_call_out", delay, func, args) ;
}

static nomask varargs int limit_call_out(string func, mixed args) {
    get_object("/system/player#12")->catch_tell("lick me, "+func+"!\n") ;
    rlimits (MAX_DEPTH; MAX_TICKS) {
        return call_other(this_object(), func, args);
    }
}
*/
